from django.db import models
from django.utils import timezone
from datetime import timedelta
from .base_model import BaseModel
from .grade import Grade
from .semester import Semester

class GradeSchedule(BaseModel):
    created_at = models.DateTimeField(default=timezone.now, verbose_name="创建时间")
    """年级日程表类，用于设置特定年级特定学期的上课和休息日期。"""
    grade = models.ForeignKey(Grade, on_delete=models.CASCADE, verbose_name='年级', related_name='school_schedules', default=1)
    semester = models.ForeignKey(Semester, on_delete=models.CASCADE, verbose_name='学期', related_name='school_schedules', default=1)
    date = models.DateField(verbose_name='日期')
    IS_CLASS_DAY_CHOICES = (
        (1, '正常上课'),
        (2, '调休'),
        (3, '课后服务'),
        (4, '考试'),
        (0, '休息日'),
    )
    is_class_day = models.IntegerField(choices=IS_CLASS_DAY_CHOICES, verbose_name='是否上课')

    class Meta:
        verbose_name = '学校日程表'
        verbose_name_plural = '学校日程表'
        ordering = ['date']
        unique_together = ('grade', 'semester', 'date')

    def get_weekday(self):
        """返回日期对应的星期几。"""
        return self.date.strftime('%A')

    @classmethod
    def display_calendar(cls, year, month):
        """以日历形式显示指定年月的日程安排。"""
        import calendar
        cal = calendar.monthcalendar(year, month)
        schedule_data = cls.objects.filter(date__year=year, date__month=month)
        schedule_dict = {item.date.day: item.is_class_day for item in schedule_data}
        result = []
        for week in cal:
            week_data = []
            for day in week:
                if day == 0:
                    week_data.append(' ')
                else:
                    status = '课' if schedule_dict.get(day, False) else '休'
                    week_data.append(f'{day}({status})')
            result.append(' '.join(week_data))
        return '\n'.join(result)

    @staticmethod
    def check_class_day(date):
        """
        根据学校日程表判断指定日期是否是上课日。

        :param date: 要判断的日期
        :return: True 如果是上课日,False 否则为休息日
        """
        try:
            schedule = GradeSchedule.objects.get(date=date)
            return schedule.is_class_day
        except GradeSchedule.DoesNotExist:
            return False

    @staticmethod
    def get_next_class_day(date):
        """
        根据学校日程表判断指定日期的下一个上课日。

        :param date: 要判断的日期
        :return: 下一个上课日的日期对象，如果没有下一个上课日则返回None
        """
        # 从当前日期的下一天开始循环判断
        current_date = date + timedelta(days=1)
        
        # 设置一个合理的查找范围，避免无限循环
        max_days = 365
        days_checked = 0
        
        while days_checked < max_days:
            if GradeSchedule.check_class_day(current_date):
                return current_date
            current_date += timedelta(days=1)
            days_checked += 1
            
        return None  # 如果在最大查找范围内没有找到上课日

    @staticmethod
    def get_prev_class_day(date):
        """
        根据学校日程表判断指定日期的上一个上课日。

        :param date: 要判断的日期
        :return: 上一个上课日的日期对象，如果没有上一个上课日则返回None
        """
        # 从当前日期的前一天开始循环判断
        current_date = date - timedelta(days=1)
        
        # 设置一个合理的查找范围，避免无限循环
        max_days = 365
        days_checked = 0
        
        while days_checked < max_days:
            if GradeSchedule.check_class_day(current_date):
                return current_date
            current_date -= timedelta(days=1)
            days_checked += 1
            
        return None  # 如果在最大查找范围内没有找到上课日

    @classmethod
    def generate_month_schedule(cls, grade_id, semester_id, year, month):
        """
        一键生成指定年级、学期、年份和月份的课程安排
        
        :param grade_id: 年级ID
        :param semester_id: 学期ID
        :param year: 年份
        :param month: 月份
        :return: 生成的课程安排数量
        """
        from datetime import date, timedelta
        import calendar
        
        # 获取月份的第一天和最后一天
        first_day = date(year, month, 1)
        last_day = date(year, month, calendar.monthrange(year, month)[1])
        
        # 清空该年级、学期、月份已有的课程安排
        cls.objects.filter(
            grade_id=grade_id,
            semester_id=semester_id,
            date__year=year,
            date__month=month
        ).delete()
        
        # 生成新的课程安排
        count = 0
        current_date = first_day
        
        while current_date <= last_day:
            # 默认为工作日(周一至周五)上课，周末休息
            weekday = current_date.weekday()
            if 0 <= weekday <= 4:
                is_class_day = 1  # 正常上课
            else:
                is_class_day = 0  # 休息日
            
            # 创建课程安排
            cls.objects.create(
                grade_id=grade_id,
                semester_id=semester_id,
                date=current_date,
                is_class_day=is_class_day
            )
            count += 1
            
            # 移动到下一天
            current_date += timedelta(days=1)
        
        return count
